package main

import (
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"my-go-chat/message"
	"net"
)

func readPkg(conn net.Conn) (mes message.Message, err error) {
	buf := make([]byte, 8096)
	fmt.Println("等待读取客户端发送的数据")
	//conn.Read  只有在conn没有被关闭的情况下 才会被阻塞
	n, err := conn.Read(buf[:4])
	if n != 4 || err != nil {
		err = fmt.Errorf("open header error %w ", err)
		return
	}
	//根据buf读取的长度转换为一个uint32类型
	pkgLen := binary.BigEndian.Uint32(buf[0:4])
	//根据pkgLen 读取消息内容
	n, err = conn.Read(buf[:pkgLen])
	if n != int(pkgLen) || err != nil {
		err = fmt.Errorf("lost package error %w ", err)
		return
	}
	//一切正常后 把数据反序列化为 message.Message
	err = json.Unmarshal(buf[:pkgLen], &mes)
	if err != nil {
		err = fmt.Errorf("unmarshal pkg error %w ", err)
		return
	}
	return
}

func writePkg(conn net.Conn, data []byte) (err error) {
	//先发送一个长度给对方
	pkgLen := uint32(len(data))
	var bytes [4]byte
	//这里使用了binary包下的方法 将uint长度值转换为字节数组
	binary.BigEndian.PutUint32(bytes[0:4], pkgLen)
	//发送长度
	n, err := conn.Write(bytes[0:4])
	if n != 4 || err != nil {
		err = fmt.Errorf("conn.write len err =  %w ", err)
		return
	}

	fmt.Println("服务器发送消息长度成功!")

	_, err = conn.Write(data)
	if err != nil {
		err = fmt.Errorf("conn.write data err =  %w ", err)
		return
	}
	return
}

//serverProcessLogin函数 专门处理登录请求
func serverProcessLogin(conn net.Conn, mes *message.Message) (err error) {
	// 先从mes 中取出mes.Data 并直接反序列化威威LoginMes
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), loginMes)
	if err != nil {
		err = fmt.Errorf("登录信息反序列化失败 : %w", err)
		return
	}

	//1先声明一个resMes
	var resMes message.Message
	resMes.Type = message.LoginResMesType

	//2再申明一个LoginResMes
	var LoginResMes message.LoginResMes

	//如果用户id 为100  ，密码123456 就是合法
	if loginMes.UserId == 100 && loginMes.UserPwd == "123456" {
		//合法
		LoginResMes.Code = 200
	} else {
		//不合法
		LoginResMes.Code = 500 //表示该用户不存在
		LoginResMes.Error = "用户不存在,请先注册"
	}

	//3将 loginResMes 序列化
	data, err := json.Marshal(LoginResMes)
	if err != nil {
		err = fmt.Errorf("登录结果返回失败！ data : %w", err)
		return
	}

	//4. 将data赋值给resMes
	resMes.Data = string(data)

	//5. 对resMes进行序列化 准备发送
	data, err = json.Marshal(resMes)
	if err != nil {
		err = fmt.Errorf("登录结果返回失败！ resMes: %w", err)
		return
	}

	//6。发送data ，我们将其封装到一个writePkg函数中

}

//编写ServerProcessMes 函数
// 功能：根据客户端发送消息种类的不同，决定调用哪个函数来处理
func ServerProcessMes(conn net.Conn, mes *message.Message) (err error) {
	switch mes.Type {
	case message.LoginMesType:
		//处理登录逻辑
		err = serverProcessLogin(conn, mes)
	case message.RegisterMes:

	case message.LoginResMesType:

	default:
		err = fmt.Errorf("消息类型无法处理!")
	}
	return
}

func Process(conn net.Conn) {
	//操作客户端的连接  读取客户端发送的消息
	defer conn.Close()

	for {
		//这里将读取数据包的工作封装为一个函数readpkg 返回message err
		mes, err := readPkg(conn)
		if err != nil {
			fmt.Println("read package error", err)
			err = errors.Unwrap(err)
			if err == io.EOF {
				fmt.Println("客户端退出！")
				return
			}
		}
		fmt.Println("mes = ", mes)
	}
}

func main() {
	fmt.Println("服务启动，在8889端口启动的监听 . . . . ")
	listen, err := net.Listen("tcp", "0.0.0.0:8889")
	defer listen.Close()
	if err != nil {
		log.Panic("net.Listen err = ", err)
	}
	fmt.Println("服务启动成功，等待客户端连接服务器中...")
	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("listen .Accept err = ", err)
		}
		go Process(conn)
	}

}
